﻿using CoreWCF;
using SD.Infrastructure.DTOBase;
using SlamDunk.MES.AppService.Maps;
using SlamDunk.MES.Domain.Entities.ConfigurationContext;
using SlamDunk.MES.Domain.Entities.DefinitionContext;
using SlamDunk.MES.Domain.Entities.FoundationContext;
using SlamDunk.MES.Domain.Entities.ResourceContext;
using SlamDunk.MES.Domain.IRepositories;
using SlamDunk.MES.Domain.Mediators;
using SlamDunk.MES.IAppService.DTOs.Inputs;
using SlamDunk.MES.IAppService.DTOs.Outputs.ConfigurationContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.DefinitionContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.FoundationContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.ResourceContext;
using SlamDunk.MES.IAppService.Interfaces;
using SlamDunk.ValueObjects.Enums;
using System;
using System.Collections.Generic;
using System.Linq;

namespace SlamDunk.MES.AppService.Implements
{
    /// <summary>
    /// 配置管理服务契约实现
    /// </summary>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, IncludeExceptionDetailInFaults = true)]
    public class ConfigurationContract : IConfigurationContract
    {
        #region # 字段及构造器

        /// <summary>
        /// 仓储中介者
        /// </summary>
        private readonly RepositoryMediator _repMediator;

        /// <summary>
        /// 单元事务
        /// </summary>
        private readonly IUnitOfWorkMES _unitOfWork;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public ConfigurationContract(RepositoryMediator repMediator, IUnitOfWorkMES unitOfWork)
        {
            this._repMediator = repMediator;
            this._unitOfWork = unitOfWork;
        }

        #endregion


        //命令部分

        #region # 保存用户扩展 —— void SaveUserExtension(string loginId, Guid personId...
        /// <summary>
        /// 保存用户扩展
        /// </summary>
        /// <param name="loginId">用户账号</param>
        /// <param name="personId">人员Id</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="terminalIds">终端Id集</param>
        /// <param name="processSegmentIds">工段Id集</param>
        /// <param name="relatedStorageLocationParams">用户相关储存位置参数模型集</param>
        public void SaveUserExtension(string loginId, Guid personId, Guid facilityId, IEnumerable<Guid> terminalIds, IEnumerable<Guid> processSegmentIds, IEnumerable<UserRelatedStorageLocationParam> relatedStorageLocationParams)
        {
            terminalIds = terminalIds?.Distinct().ToArray() ?? Array.Empty<Guid>();
            processSegmentIds = processSegmentIds?.Distinct().ToArray() ?? Array.Empty<Guid>();
            relatedStorageLocationParams = relatedStorageLocationParams?.ToArray() ?? Array.Empty<UserRelatedStorageLocationParam>();
            IEnumerable<UserRelatedTerminal> relatedTerminals =
                from terminalId in terminalIds
                select new UserRelatedTerminal(terminalId);
            IDictionary<Guid, ProcessSegment> processSegments = this._repMediator.ProcessSegmentRep.Find(processSegmentIds);
            IEnumerable<UserRelatedProcessSegment> relatedProcessSegments =
                from processSegmentId in processSegmentIds
                let processSegement = processSegments[processSegmentId]
                select new UserRelatedProcessSegment(processSegement.Process.Id, processSegement.Id);
            IEnumerable<UserRelatedStorageLocation> relatedStorageLocations =
                from param in relatedStorageLocationParams
                select new UserRelatedStorageLocation(param.storageLocationType, param.storageLocationId, param.storageLocationName, param.isAutoStockIn);

            if (this._repMediator.UserExtensionRep.ExistsNo(loginId))
            {
                UserExtension userExtension = this._unitOfWork.Resolve<UserExtension>(loginId);
                userExtension.UpdateInfo(personId, facilityId);
                userExtension.RelateTerminals(relatedTerminals);
                userExtension.RelateProcessSegments(relatedProcessSegments);
                userExtension.RelateStorageLocations(relatedStorageLocations);

                this._unitOfWork.RegisterSave(userExtension);
            }
            else
            {
                UserExtension userExtension = new UserExtension(loginId, personId, facilityId);
                userExtension.RelateTerminals(relatedTerminals);
                userExtension.RelateProcessSegments(relatedProcessSegments);
                userExtension.RelateStorageLocations(relatedStorageLocations);

                this._unitOfWork.RegisterAdd(userExtension);
            }

            this._unitOfWork.Commit();
        }
        #endregion

        #region # 创建终端 —— void CreateTerminal(string terminalNo, string terminalName...
        /// <summary>
        /// 创建终端
        /// </summary>
        /// <param name="terminalNo">终端编号</param>
        /// <param name="terminalName">终端名称</param>
        /// <param name="description">描述</param>
        public void CreateTerminal(string terminalNo, string terminalName, string description)
        {
            Terminal terminal = new Terminal(terminalNo, terminalName, description);

            this._unitOfWork.RegisterAdd(terminal);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改终端 —— void UpdateTerminal(Guid terminalId, string terminalNo...
        /// <summary>
        /// 修改终端
        /// </summary>
        /// <param name="terminalId">终端Id</param>
        /// <param name="terminalNo">终端编号</param>
        /// <param name="terminalName">终端名称</param>
        /// <param name="description">描述</param>
        public void UpdateTerminal(Guid terminalId, string terminalNo, string terminalName, string description)
        {
            Terminal terminal = this._unitOfWork.Resolve<Terminal>(terminalId);
            terminal.UpdateInfo(terminalNo, terminalName, description);

            this._unitOfWork.RegisterSave(terminal);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 删除终端 —— void RemoveTerminal(Guid terminalId)
        /// <summary>
        /// 删除终端
        /// </summary>
        /// <param name="terminalId">终端Id</param>
        public void RemoveTerminal(Guid terminalId)
        {
            this._unitOfWork.RegisterRemove<Terminal>(terminalId);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 创建硬件 —— void CreateHardware(string hardwareNo, string hardwareName...
        /// <summary>
        /// 创建硬件
        /// </summary>
        /// <param name="hardwareNo">硬件编号</param>
        /// <param name="hardwareName">硬件名称</param>
        /// <param name="hardwareType">硬件类型</param>
        /// <param name="model">型号</param>
        /// <param name="description">描述</param>
        public void CreateHardware(string hardwareNo, string hardwareName, HardwareType hardwareType, string model, string description)
        {
            Hardware hardware = new Hardware(hardwareNo, hardwareName, hardwareType, model, description);

            this._unitOfWork.RegisterAdd(hardware);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改硬件 —— void UpdateHardware(Guid hardwareId, string hardwareNo...
        /// <summary>
        /// 修改硬件
        /// </summary>
        /// <param name="hardwareId">硬件Id</param>
        /// <param name="hardwareNo">硬件编号</param>
        /// <param name="hardwareName">硬件名称</param>
        /// <param name="model">型号</param>
        /// <param name="description">描述</param>
        public void UpdateHardware(Guid hardwareId, string hardwareNo, string hardwareName, string model, string description)
        {
            Hardware hardware = this._unitOfWork.Resolve<Hardware>(hardwareId);
            hardware.UpdateInfo(hardwareNo, hardwareName, model, description);

            this._unitOfWork.RegisterSave(hardware);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 删除硬件 —— void RemoveHardware(Guid hardwareId)
        /// <summary>
        /// 删除硬件
        /// </summary>
        /// <param name="hardwareId">硬件Id</param>
        public void RemoveHardware(Guid hardwareId)
        {
            this._unitOfWork.RegisterRemove<Hardware>(hardwareId);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 配置硬件网口通信 —— void ConfigureHardwareNetworkMode(Guid hardwareId...
        /// <summary>
        /// 配置硬件网口通信
        /// </summary>
        /// <param name="hardwareId">硬件Id</param>
        /// <param name="terminalId">终端Id</param>
        /// <param name="ipAddress">IP地址</param>
        /// <param name="port">端口号</param>
        public void ConfigureHardwareNetworkMode(Guid hardwareId, Guid? terminalId, string ipAddress, int port)
        {
            Hardware hardware = this._unitOfWork.Resolve<Hardware>(hardwareId);
            hardware.ConfigureNetworkMode(terminalId, ipAddress, port);

            this._unitOfWork.RegisterSave(hardware);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 配置硬件串口通信 —— void ConfigureHardwareSerialPortMode(Guid hardwareId...
        /// <summary>
        /// 配置硬件串口通信
        /// </summary>
        /// <param name="hardwareId">硬件Id</param>
        /// <param name="terminalId">终端Id</param>
        /// <param name="comPort">串口端口号</param>
        /// <param name="baudRate">波特率</param>
        /// <param name="stopBit">停止位</param>
        /// <param name="parityBit">校验位</param>
        /// <param name="dataBit">数据位</param>
        /// <param name="dtr">数据终端准备</param>
        /// <param name="rts">请求发送</param>
        public void ConfigureHardwareSerialPortMode(Guid hardwareId, Guid? terminalId, string comPort, int baudRate, StopBits stopBit, Parity parityBit, int dataBit, bool dtr, bool rts)
        {
            Hardware hardware = this._unitOfWork.Resolve<Hardware>(hardwareId);
            hardware.ConfigureSerialPortMode(terminalId, comPort, baudRate, stopBit, parityBit, dataBit, dtr, rts);

            this._unitOfWork.RegisterSave(hardware);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 配置硬件USB口通信 —— void ConfigureHardwareUsbMode(Guid hardwareId, Guid? terminalId)
        /// <summary>
        /// 配置硬件USB口通信
        /// </summary>
        /// <param name="hardwareId">硬件Id</param>
        /// <param name="terminalId">终端Id</param>
        public void ConfigureHardwareUsbMode(Guid hardwareId, Guid? terminalId)
        {
            Hardware hardware = this._unitOfWork.Resolve<Hardware>(hardwareId);
            hardware.ConfigureUsbMode(terminalId);

            this._unitOfWork.RegisterSave(hardware);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 创建工作通知 —— void CreateNotification(string title, string content...
        /// <summary>
        /// 创建工作通知
        /// </summary>
        /// <param name="title">标题</param>
        /// <param name="content">内容</param>
        /// <param name="issuedDate">下发日期</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="priority">优先级</param>
        /// <param name="description">描述</param>
        public void CreateNotification(string title, string content, DateTime issuedDate, Guid? facilityId, int priority, string description)
        {
            Notification notification = new Notification(title, content, issuedDate, facilityId, priority, description);

            this._unitOfWork.RegisterAdd(notification);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 删除工作通知 —— void RemoveNotification(Guid notificationId)
        /// <summary>
        /// 删除工作通知
        /// </summary>
        /// <param name="notificationId">工作通知Id</param>
        public void RemoveNotification(Guid notificationId)
        {
            this._unitOfWork.RegisterRemove<Notification>(notificationId);
            this._unitOfWork.Commit();
        }
        #endregion


        //查询部分

        #region # 分页获取用户扩展列表 —— PageModel<UserExtensionInfo> GetUserExtensionsByPage(Guid? facilityId...
        /// <summary>
        /// 分页获取用户扩展列表
        /// </summary>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>用户扩展列表</returns>
        public PageModel<UserExtensionInfo> GetUserExtensionsByPage(Guid? facilityId, int pageIndex, int pageSize)
        {
            Facility facility = facilityId.HasValue
                ? this._repMediator.FacilityRep.SingleFully(facilityId.Value)
                : null;
            IList<Guid> relatedFacilityIds = facility?.GetDeepNodeIds();

            ICollection<UserExtension> userExtensions = this._repMediator.UserExtensionRep.FindByPage(relatedFacilityIds, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> personIds = userExtensions.Select(x => x.PersonId);
            IEnumerable<Guid> facilityIds = userExtensions.Select(x => x.FacilityId);
            IDictionary<Guid, PersonInfo> personInfos = this._repMediator.PersonRep.Find(personIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));
            IDictionary<Guid, FacilityInfo> facilityInfos = this._repMediator.FacilityRep.Find(facilityIds).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<UserExtensionInfo> userExtensionInfos = userExtensions.Select(x => x.ToDTO(personInfos, facilityInfos));

            return new PageModel<UserExtensionInfo>(userExtensionInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 获取用户扩展 —— UserExtensionInfo GetUserExtension(string loginId)
        /// <summary>
        /// 获取用户扩展
        /// </summary>
        /// <param name="loginId">用户账号</param>
        /// <returns>用户扩展信息</returns>
        public UserExtensionInfo GetUserExtension(string loginId)
        {
            UserExtension userExtension = this._repMediator.UserExtensionRep.SingleOrDefault(loginId);
            if (userExtension == null)
            {
                return null;
            }

            //用户相关人员
            Person person = this._repMediator.PersonRep.Single(userExtension.PersonId);
            PersonInfo personInfo = person.ToDTO(null);

            //用户相关班组
            Team team = this._repMediator.TeamRep.SingleOrDefaultByPerson(person.Id);
            TeamInfo teamInfo = team?.ToDTO(null);

            //用户相关工厂模型
            Facility facility = this._repMediator.FacilityRep.Single(userExtension.FacilityId);
            FacilityInfo facilityInfo = facility.ToDTO();

            //用户相关终端
            ICollection<UserRelatedTerminal> relatedTerminals = this._repMediator.UserRelatedTerminalRep.Find(loginId);
            IEnumerable<Guid> terminalIds = relatedTerminals.Select(x => x.TerminalId);
            IDictionary<Guid, Terminal> terminals = this._repMediator.TerminalRep.Find(terminalIds);
            IEnumerable<TerminalInfo> relatedTerminalInfos = terminals.Values.Select(x => x.ToDTO());

            //用户相关工艺段
            ICollection<UserRelatedProcessSegment> relatedProcessSegments = this._repMediator.UserRelatedProcessSegmentRep.Find(loginId);
            IEnumerable<Guid> processSegmentIds = relatedProcessSegments.Select(x => x.ProcessSegmentId);
            IDictionary<Guid, ProcessSegment> processSegments = this._repMediator.ProcessSegmentRep.Find(processSegmentIds);
            IEnumerable<ProcessSegmentInfo> relatedProcessSegmentInfos = processSegments.Values.Select(x => x.ToDTO(null, null));

            //用户相关储存位置
            ICollection<UserRelatedStorageLocation> relatedStorageLocations = this._repMediator.UserRelatedStorageLocationRep.Find(loginId);
            IEnumerable<UserRelatedStorageLocationInfo> relatedStorageLocationInfos = relatedStorageLocations.Select(x => x.ToDTO());

            UserExtensionInfo userExtensionInfo = userExtension.ToDTO(null, null);
            userExtensionInfo.PersonInfo = personInfo;
            userExtensionInfo.TeamInfo = teamInfo;
            userExtensionInfo.FacilityInfo = facilityInfo;
            userExtensionInfo.RelatedTerminalInfos = relatedTerminalInfos;
            userExtensionInfo.RelatedProcessSegmentInfos = relatedProcessSegmentInfos;
            userExtensionInfo.RelatedStorageLocationInfos = relatedStorageLocationInfos;

            return userExtensionInfo;
        }
        #endregion

        #region # 获取用户相关终端列表 —— IEnumerable<TerminalInfo> GetUserRelatedTerminals(string loginId)
        /// <summary>
        /// 获取用户相关终端列表
        /// </summary>
        /// <param name="loginId">用户账号</param>
        /// <returns>用户相关终端列表</returns>
        public IEnumerable<TerminalInfo> GetUserRelatedTerminals(string loginId)
        {
            ICollection<UserRelatedTerminal> relatedTerminals = this._repMediator.UserRelatedTerminalRep.Find(loginId);
            IEnumerable<Guid> terminalIds = relatedTerminals.Select(x => x.TerminalId);
            IDictionary<Guid, Terminal> terminals = this._repMediator.TerminalRep.Find(terminalIds);
            IEnumerable<TerminalInfo> terminalInfos = terminals.Values.Select(x => x.ToDTO());

            return terminalInfos;
        }
        #endregion

        #region # 获取用户相关工艺段列表 —— {ProcessInfo, ProcessSegmentInfo[]} GetUserRelatedProcessSegments(...
        /// <summary>
        /// 获取用户相关工艺段列表
        /// </summary>
        /// <param name="loginId">用户账号</param>
        /// <returns>用户相关工艺段列表</returns>
        public IDictionary<ProcessInfo, ProcessSegmentInfo[]> GetUserRelatedProcessSegments(string loginId)
        {
            ICollection<UserRelatedProcessSegment> relatedProcessSegments = this._repMediator.UserRelatedProcessSegmentRep.Find(loginId);
            IEnumerable<Guid> processSegmentIds = relatedProcessSegments.Select(x => x.ProcessSegmentId);
            IDictionary<Guid, ProcessSegment> processSegments = this._repMediator.ProcessSegmentRep.Find(processSegmentIds);
            IDictionary<ProcessInfo, ProcessSegmentInfo[]> dictionary = processSegments.Values.GroupBy(x => x.Process).ToDictionary(x => x.Key.ToDTO(null, null, null), x => x.Select(y => y.ToDTO(null, null)).ToArray());

            return dictionary;
        }
        #endregion

        #region # 获取用户相关储存位置列表 —— IEnumerable<UserRelatedStorageLocationInfo> GetUserRelatedStorageLocations(...
        /// <summary>
        /// 获取用户相关储存位置列表
        /// </summary>
        /// <param name="loginId">用户账号</param>
        /// <returns>用户相关储存位置列表</returns>
        public IEnumerable<UserRelatedStorageLocationInfo> GetUserRelatedStorageLocations(string loginId)
        {
            ICollection<UserRelatedStorageLocation> relatedStorageLocations = this._repMediator.UserRelatedStorageLocationRep.Find(loginId);
            IEnumerable<UserRelatedStorageLocationInfo> relatedStorageLocationInfos = relatedStorageLocations.Select(x => x.ToDTO());

            return relatedStorageLocationInfos;
        }
        #endregion

        #region # 分页获取终端列表 —— PageModel<TerminalInfo> GetTerminalsByPage(string keywords...
        /// <summary>
        /// 分页获取终端列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>终端列表</returns>
        public PageModel<TerminalInfo> GetTerminalsByPage(string keywords, int pageIndex, int pageSize)
        {
            ICollection<Terminal> terminals = this._repMediator.TerminalRep.FindByPage(keywords, pageIndex, pageSize, out int rowCount, out int pageCount);
            IEnumerable<TerminalInfo> terminalInfos = terminals.Select(x => x.ToDTO());

            return new PageModel<TerminalInfo>(terminalInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 获取终端 —— TerminalInfo GetTerminal(string terminalNo)
        /// <summary>
        /// 获取终端
        /// </summary>
        /// <param name="terminalNo">终端编号</param>
        /// <returns>终端</returns>
        public TerminalInfo GetTerminal(string terminalNo)
        {
            Terminal terminal = this._repMediator.TerminalRep.Single(terminalNo);
            TerminalInfo terminalInfo = terminal.ToDTO();

            return terminalInfo;
        }
        #endregion

        #region # 分页获取硬件列表 —— PageModel<HardwareInfo> GetHardwaresByPage(string keywords...
        /// <summary>
        /// 分页获取硬件列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="hardwareType">硬件类型</param>
        /// <param name="terminalId">终端Id</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>硬件列表</returns>
        public PageModel<HardwareInfo> GetHardwaresByPage(string keywords, HardwareType? hardwareType, Guid? terminalId, int pageIndex, int pageSize)
        {
            ICollection<Hardware> hardwares = this._repMediator.HardwareRep.FindByPage(keywords, hardwareType, terminalId, pageIndex, pageSize, out int rowCount, out int pageCount);
            IEnumerable<HardwareInfo> hardwareInfos = hardwares.Select(x => x.ToDTO());

            return new PageModel<HardwareInfo>(hardwareInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 分页获取工作通知列表 —— PageModel<NotificationInfo> GetNotificationsByPage(string keywords...
        /// <summary>
        /// 分页获取工作通知列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>工作通知列表</returns>
        public PageModel<NotificationInfo> GetNotificationsByPage(string keywords, Guid? facilityId, DateTime? startTime, DateTime? endTime, int pageIndex, int pageSize)
        {
            Facility facility = facilityId.HasValue
                ? this._repMediator.FacilityRep.SingleFully(facilityId.Value)
                : null;
            IList<Guid> relatedFacilityIds = facility?.GetDeepNodeIds();

            ICollection<Notification> notifications = this._repMediator.NotificationRep.FindByPage(keywords, relatedFacilityIds, startTime, endTime, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> facilityIds = notifications.Where(x => x.FacilityId.HasValue).Select(x => x.FacilityId.Value);
            IDictionary<Guid, FacilityInfo> facilityInfos = this._repMediator.FacilityRep.Find(facilityIds).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<NotificationInfo> notificationInfos = notifications.Select(x => x.ToDTO(facilityInfos));

            return new PageModel<NotificationInfo>(notificationInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion
    }
}
